﻿using System;
using System.Collections.ObjectModel;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using BestCode.Creds.Business;
using BestCode.Creds.Entities;
using BestCode.Creds.UI.Config;
using System.Collections.Generic;
using BestCode.Creds.Media;

namespace BestCode.Creds.UI.Core
{
    public class CredentialGenerator
    {
        #region properties

        private ObservableCollection<FieldDefinition> Items;
        private ObservableCollection<FieldDefinition> EnabledItems
        {
            get
            {
                return new ObservableCollection<FieldDefinition>(Items.Where(p => p.IsEnabled));
            }
        }

        public event EventHandler onCredentialGenerated;


        private Template AnverseFace
        {
            get
            {
                return Items.FirstOrDefault().Entity.AnverseFace;
            }

        }

        private Template ReverseFace
        {
            get
            {
                if (Items.FirstOrDefault().Entity.ReverseFace==null)
                    throw new Exception("Reverse Face Not Found!!!!");


                return Items.FirstOrDefault().Entity.ReverseFace;
            }

        }


        private EntityInfo Entity
        {
            get
            {
                return Items.FirstOrDefault().Entity;
            }

        }

        
        public string OutputFolder
        {
            get { return ConfigReader.Current.Config.DefaultOutputFolder; }
        }

        public string PrinterName
        {
            get { return ConfigReader.Current.Config.DefaultPrinterName; }
        }

        #endregion

        #region constructor

        public CredentialGenerator()
        {
            InstanciateMediaRepository();
        }

        #endregion

        #region MEDIA DATABASE RESOURCES
       
        private ICredsMediaFeatures mediaRepository = null;

        public void InstanciateMediaRepository()
        {
            try
            {
                String mediaDBFullClassName = System.Configuration.ConfigurationManager.AppSettings["MediaDBFullClassName"];
                mediaRepository = (ICredsMediaFeatures)BestCode.Core.Reflection.InstanciateObjectFromAssembly(mediaDBFullClassName);

                if (mediaRepository == null)
                   MessageBox.Show("Media DataBase from FullClassName cannot be instantiated!!!");

            }
            catch (Exception exe)
            {
                MessageBox.Show("Media DataBase cannot be instantiated!!!" + (exe.InnerException != null ? exe.InnerException.Message : exe.Message));
            }
        }

        #endregion


        public void Do(ObservableCollection<FieldDefinition> items)
        {
            //verifying license



            Items = items;
            Generate(ReverseFace);

            if(ReverseFace.Id != AnverseFace.Id)
               Generate(AnverseFace);
        }


        private System.Drawing.Image ByteArrayToImagesssss(byte[] myByteArray)
        {
            MemoryStream ms = new MemoryStream(myByteArray, 0, myByteArray.Length);
            ms.Write(myByteArray, 0, myByteArray.Length);
            return System.Drawing.Image.FromStream(ms);
        }

        public void Generate(Template face)
        {
            string credencialImage = face.FaceImagePath;

            //loading image from template
            AttachmentBusiness attachmentBusiness = new AttachmentBusiness();
            var attachment = attachmentBusiness.Get(face.AttachmentId);
            if (attachment.MediaContent == null)
                throw new Exception("Attachment Content is wrong or null.");



            var a = new DirectoryInfo(OutputFolder);
            var entityfolder = a.CreateSubdirectory(Entity.Code);
            
            //getting fields from layout
            LayoutBusiness layoutBusiness = new LayoutBusiness();
            List<Layout> layoutItems = layoutBusiness.LoadByTemplateId(face.Id).ToList();

            int counter = 1;

                foreach (var fieldDefinition in EnabledItems)
                {
                    //reading face from phisical path
                    //System.Drawing.Image canvas = Bitmap.FromFile(credencialImage);
                    //Graphics gra = Graphics.FromImage(canvas);

                    System.Drawing.Image canvas = ByteArrayToImage(attachment.MediaContent);
                    Graphics gra = Graphics.FromImage(canvas);

                    #region GetValues from layout

                    foreach (var layoutItem in layoutItems)
                    {
                        if(layoutItem.IsDisabled) continue;

                        if (layoutItem.IsPicturePath)
                        {
                            string picturesFolder = fieldDefinition.EntityChild != null
                                                   ? fieldDefinition.EntityChild.PicturesFolder
                                                   : fieldDefinition.Entity.PicturesFolder;

                            var picture = picturesFolder + "\\" + fieldDefinition.Picture;

                            if(!File.Exists(picture))
                                throw new Exception(string.Format("Picture {0}, from {1} not exists!!!!, generation will stopped", picture, fieldDefinition.FullName));

                            Bitmap smallImg = new Bitmap(picture);
                            var resizedPicture = resizeImage(smallImg, new System.Drawing.Size() { Height = layoutItem.Height , Width = layoutItem.Width });
                            gra.DrawImage(resizedPicture, new System.Drawing.Point(Convert.ToInt32(layoutItem.X), Convert.ToInt32(layoutItem.Y)));
                        }
                        else if (layoutItem.IsQRCode)
                        {
                             var stringValue = fieldDefinition.GetType()
                                .GetProperties()
                                .Where(
                                    pi =>
                                        pi.PropertyType == typeof (string) && pi.GetGetMethod() != null &&
                                        pi.Name.Equals(layoutItem.FieldName))
                                .Select(pi => pi.GetGetMethod().Invoke(fieldDefinition, null)).FirstOrDefault();
                            var image =
                                        BestCode.Utils.CodeBars.Common.GenerateQRCode(stringValue == null ? "" : stringValue.ToString(), System.Drawing.Imaging.ImageFormat.Png);

                            if (ConfigReader.Current.Config.CanResizeQRCode) 
                            {
                                if(layoutItem.Height <= 0 || layoutItem.Width <=0)
                                    throw new Exception("QR Image to Resize cannot be 0");

                                var imageObject = ByteArrayToImage(image);
                                var resizedQR = resizeImage(imageObject,
                                    new System.Drawing.Size() {Height = layoutItem.Height, Width = layoutItem.Width});

                                gra.DrawImage(resizedQR,
                                    new System.Drawing.Point(Convert.ToInt32(layoutItem.X),
                                        Convert.ToInt32(layoutItem.Y)));
                            }
                            else
                            {
                                gra.DrawImage(ByteArrayToImage(image), new System.Drawing.Point(Convert.ToInt32(layoutItem.X), Convert.ToInt32(layoutItem.Y)));
                            }
                        }
                        else
                        {
                            var stringValue = fieldDefinition.GetType()
                                .GetProperties()
                                .Where(
                                    pi =>
                                        pi.PropertyType == typeof (string) && pi.GetGetMethod() != null &&
                                        pi.Name.Equals(layoutItem.FieldName))
                                .Select(pi => pi.GetGetMethod().Invoke(fieldDefinition, null)).FirstOrDefault();

                            //var converter = new System.Windows.Media.BrushConverter();
                            //var brush = (Brush)converter.ConvertFromString("#FFFFFF90");


                            gra.DrawString(stringValue == null ? "" : stringValue.ToString(),
                                new Font(layoutItem.FontFamily, layoutItem.FontSize, GetFontStyle(layoutItem.FontWeight)),
                                
                                new SolidBrush(System.Drawing.ColorTranslator.FromHtml(layoutItem.Color)), 
                                
                                new System.Drawing.Point(Convert.ToInt32(layoutItem.X), Convert.ToInt32(layoutItem.Y)));

                            //var mySolidColorBrush = new System.Windows.Media.SolidColorBrush();
                            //mySolidColorBrush = (System.Windows.Media.SolidColorBrush)(new System.Windows.Media.BrushConverter().ConvertFrom("#ffaacc"));

                            /*new SolidBrush(Color.FromArgb(0x78FF0000)),
                             * var s1=   System.Drawing.ColorTranslator.FromHtml("#FFFFFF");
                            var s2 = new SolidBrush(Color.FromName("#FFB2494B"));
                            var s3 = new SolidBrush(Color.FromName("Yellow"));
                            var color = new SolidBrush(Color.Black);*/
                        }
                    }

                    #endregion

                    var subFolder = fieldDefinition.EntityChild != null
                        ? entityfolder.CreateSubdirectory(fieldDefinition.EntityChild.Name+"_"+face.Name)
                        : entityfolder;

                    var fileName = subFolder.ToString() + "\\" + fieldDefinition.Picture + ".png";
                    canvas.Save(fileName, System.Drawing.Imaging.ImageFormat.Png);
                    
                    /*********************SAVING IN MEDIA DATA BASE ********************/

                    if (mediaRepository != null)
                    {
                        if ((face.Id == AnverseFace.Id))
                        {
                            var dbfileName = fieldDefinition.Entity.Id + "-" +
                                             ((fieldDefinition.EntityChild != null) ? fieldDefinition.EntityChild.Id : 0) +
                                             "-" +
                                             fieldDefinition.Picture;


                            mediaRepository.Save(fieldDefinition.Id,
                                fieldDefinition.Entity.Id,
                                (fieldDefinition.EntityChild != null) ? fieldDefinition.EntityChild.Id : 0,
                                ImageToByteArray(canvas),
                                (face.Id == AnverseFace.Id),
                                fieldDefinition.FullName,
                                dbfileName,
                                fieldDefinition.Entity.Name + " | " +
                                ((fieldDefinition.EntityChild != null) ? fieldDefinition.EntityChild.Name : ""));
                        }
                    }
                    /*******************************************************************/
                    
                    canvas.Dispose();
                    gra.Dispose();
                    //smallImg.Dispose();


                    if (onCredentialGenerated != null)
                        onCredentialGenerated(counter++, EventArgs.Empty);

                }
        }

        public System.Drawing.FontStyle GetFontStyle(string fontWeight)
        {
            switch (fontWeight)
            {
                case "Bold" :
                    return System.Drawing.FontStyle.Bold;
                case "Italic" :
                    return System.Drawing.FontStyle.Italic;
                case "Underline":
                    return System.Drawing.FontStyle.Underline;
                case "Regular":
                    return System.Drawing.FontStyle.Regular;
                case "Strikeout":
                    return System.Drawing.FontStyle.Strikeout;
                default :
                    return System.Drawing.FontStyle.Regular;
            }
        }


        public static System.Drawing.Image resizeImage(System.Drawing.Image imgToResize, System.Drawing.Size size)
        {
            if (size.Height <= 0 || size.Width <= 0)
                throw new Exception("Resize dimension cannot be 0, change width and height from Layout Item");


            return (System.Drawing.Image)(new Bitmap(imgToResize, size));
        }

        public System.Drawing.Image ByteArrayToImage(byte[] byteArrayIn)
        {
            MemoryStream ms = new MemoryStream(byteArrayIn);
            System.Drawing.Image returnImage = System.Drawing.Image.FromStream(ms);
            return returnImage;
        }

        public byte[] ImageToByteArray(System.Drawing.Image imageIn)
        {
            MemoryStream ms = new MemoryStream();
            imageIn.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
            return ms.ToArray();
        }

    }
}
